﻿namespace BEGDC.Utility.Extensions
{
    #region Using Directives

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;

    #endregion

    public static class QueryExtensions
    {
        /// <summary>
        /// Creates the DataTable schema from entity definition.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <returns>A <see cref="DataTable"/> object.</returns>
        public static DataTable CreateDataTableSchemaFromEntity(Type entityType)
        {
            if (entityType == null)
            {
                throw new ArgumentNullException("entityType");
            }

            var dt = new DataTable();

            var properties = TypeDescriptor.GetProperties(entityType);

            foreach (PropertyDescriptor pi in properties)
            {
                dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
            }

            return dt;
        }

        /// <summary>
        /// Convertes entities collection to a DataTable.
        /// </summary>
        /// <typeparam name="T">Source entity type.</typeparam>
        /// <param name="items">Entities collection.</param>
        /// <returns>A <see cref="DataTable"/> object.</returns>
        /// <remarks>Entity should have a constructor.</remarks>
        public static DataTable ToDataTable<T>(this IEnumerable<T> items) where T : class
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            var dt = new DataTable();

            var properties = TypeDescriptor.GetProperties(typeof(T));

            foreach (PropertyDescriptor pi in properties)
            {
                dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
            }

            foreach (T item in items)
            {
                var row = dt.NewRow();

                foreach (PropertyDescriptor pi in properties)
                {
                    row[pi.Name] = pi.GetValue(item) ?? DBNull.Value;
                }

                dt.Rows.Add(row);
            }

            return dt;
        }

        /// <summary>
        /// Converts DataTable to entities collection.
        /// </summary>
        /// <typeparam name="T">Type of the entity.</typeparam>
        /// <param name="dt">The DataTable.</param>
        /// <returns>Entities collection.</returns>
        public static IEnumerable<T> ToEntities<T>(this DataTable dt) where T : class, new()
        {
            if (dt == null)
            {
                throw new ArgumentNullException("dt");
            }

            var properties =  TypeDescriptor.GetProperties(typeof(T)).Cast<PropertyDescriptor>().Where(pd => dt.Columns.IndexOf(pd.Name) != -1).ToList();

            foreach (DataRow row in dt.Rows)
            {
                var entity = new T();

                foreach (PropertyDescriptor pd in properties.Where(pd => !row.IsNull(pd.Name)))
                {
                    pd.SetValue(entity, row[pd.Name]);
                }

                yield return entity;
            }
        }
    }
}